package com.cx.utils;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.converters.*;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.ClassUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL;
import java.util.*;

public class BeanHelper {

    private BeanHelper() {
    }

    /**
     * 判断是否是简单值类型.包括：基础数据类型、CharSequence、Number、Date、URL、URI、Locale、Class;
     *
     * @param clazz
     * @return
     */
    public static boolean isSimpleValueType(Class<?> clazz) {
        return (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() || CharSequence.class.isAssignableFrom(clazz)
                || Number.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz) || URI.class == clazz
                || URL.class == clazz || Locale.class == clazz || Class.class == clazz);
    }

    public static void registerConvertUtils() {
        ConvertUtils.register(new StringConverter(), String.class);
        ConvertUtils.register(new Converter(){
            @Override
            public String convert(Class aClass, Object value) {
                if (value == null) {
                    return null;
                }else{
                    if(value instanceof Date ){
                        return FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.S").format(value);
                    }
                    return value.toString();
                }
            }
        }, String.class);
        //date
        DateConverter dateConverter = new DateConverter(null);
        String[] parsePatterns = {
                "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.S", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH",
                "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM/dd HH", "yyyy/MM",
                "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM.dd HH", "yyyy.MM", "yyyy",
                "yyyy年MM月dd日", "yyyy年MM月dd日 HH时mm分ss秒", "yyyy年MM月dd日 HH时mm分", "yyyy年MM月dd日 HH时", "yyyy年MM月"
        };
        dateConverter.setPatterns(parsePatterns);
        dateConverter.setLocale(Locale.CHINA);
        dateConverter.setTimeZone(TimeZone.getDefault());
        ConvertUtils.register(dateConverter, Date.class);
//        SqlTimeConverter sqlTimeConverter = new SqlTimeConverter(null);
//        sqlTimeConverter.setPatterns(parsePatterns);
//        sqlTimeConverter.setLocale(Locale.CHINA);
//        sqlTimeConverter.setTimeZone(TimeZone.getDefault());
//        ConvertUtils.register(sqlTimeConverter, Time.class);
//        SqlTimestampConverter sqlTimestampConverter = new SqlTimestampConverter(null);
//        sqlTimestampConverter.setPatterns(parsePatterns);
//        sqlTimestampConverter.setLocale(Locale.CHINA);
//        sqlTimestampConverter.setTimeZone(TimeZone.getDefault());
//        ConvertUtils.register(sqlTimestampConverter, Timestamp.class);
        //number
        ConvertUtils.register(new BooleanConverter(null), Boolean.class);
        ConvertUtils.register(new ShortConverter(null), Short.class);
        ConvertUtils.register(new IntegerConverter(null), Integer.class);
        ConvertUtils.register(new LongConverter(null), Long.class);
        ConvertUtils.register(new FloatConverter(null), Float.class);
        ConvertUtils.register(new DoubleConverter(null), Double.class);
        ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);
        ConvertUtils.register(new BigIntegerConverter(null), BigInteger.class);
    }

    /**
     * findAll缓存key
     * @param keyspace
     * @param methodname
     * @param paramnames 第一个，第二个，...依次排列
     * @param paramvals 第一个，第二个，...依次排列，和paramnames的顺序一致
     * @return
     */
    public static String key(String keyspace, String methodname, String[] paramnames, Object[] paramvals){
        StringBuffer sb = new StringBuffer(keyspace);
        sb.append(":finds").append(StringUtils.isBlank(methodname)? "" : Const.SP+methodname);
        if(ArrayUtils.isNotEmpty(paramnames) && ArrayUtils.isNotEmpty(paramvals)) {
            Arrays.stream(paramnames).filter(p->null!=p).forEach(fieldname -> {
                sb.append(Const.SP+fieldname);
            });

            Arrays.stream(paramvals).filter(p->null!=p).forEach(paramval -> {
                if (paramval instanceof List) {
                    Collections.sort((List) paramval);
                }else if (paramval instanceof Object[]) {
                    Arrays.sort((Object[]) paramval);
                }else if(paramval instanceof Sort){
                    paramval = new String(ProtoStuffUtil.serialize(paramval));
                }
                sb.append(Const.SP + paramval.hashCode());
            });
        }

        return sb.toString();
    }

    public static void getOnlyOne(String key, RedisOperations operations){
        operations.boundHashOps(key).entries();;
    }
}